﻿//========================================================= 
/**@file CCID_DevUpdater.h 
 * @brief CCID IC卡读卡器固件升级程序 
 * 
 * @date 2015-01-02   15:46:22 
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_CCID_DEVUPDATER_H_
#define _LIBZHOUYB_CCID_DEVUPDATER_H_
//--------------------------------------------------------- 
#include "../DevUpdater.h"
#include "../../../include/BaseDevice.h"
#include "../../../include/Extension.h"

#include "../../test_frame/linker/CCID_TestLinker.h"
using zhou_yb::application::test::CCID_TestLinker;

#include "../../../extension/ability/win_helper/WinCCID_EscapeCommandHelper.h"
using zhou_yb::extension::ability::WinCCID_EscapeCommandHelper;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace updater {
//--------------------------------------------------------- 
/**
 * @brief CCID读卡器切换升级模式连接器(负责发送切换指令)
 * @date 2017-03-09 21:09:38
 *
 * - 升级的操作流程:
 *  - 1.检测Name是否存在,如果存在,则根据指定的参数连接设备
 *  - 2.发送切换指令
 *  - 3.检测设备是否切换到Updater模式
 * .
 */
class CCID_UpdateModeTestLinker : public TestLinker<CCID_Device>
{
protected:
    CCID_TestLinker _ccidLinker;
public:
    /**
     * @brief 检测是否有待升级状态的设备存在,没有的话发送指令进行切换
     * 
     * @param [in] dev 需要操作的设备
     * @param [in] arg 参数列表 "[Name:<contactless>][EscapeCommand:<True|False|Auto>]"
     * @param [in] printer 文本输出器
     */
    virtual bool Link(CCID_Device& dev, IStringArguments& arg, TextPrinter& printer)
    {
        list_t<string> devlist;
        list_t<string>::iterator itr;
        dev.EnumDevice(devlist);

        string name = arg["Name"].To<string>();

        // 不需要进行切换
        if(CCID_DeviceHelper::IsExist(name.c_str(), &devlist) != DevHelper::EnumSUCCESS)
        {
            printer.TextPrint(TextPrinter::TextLogger, "未检测到需要切换的设备");
            return true;
        }

        printer.TextPrint(TextPrinter::TextLogger, "连接设备");
        if(!_ccidLinker.Link(dev, arg, printer))
        {
            printer.TextPrint(TextPrinter::TextLogger, "连接设备失败");
            return false;
        }

        printer.TextPrint(TextPrinter::TextLogger, "切换设备为升级模式");
        ByteBuilder sApdu(8);
        ByteBuilder rApdu(8);
        DevCommand::FromAscii("FF 00 82 00 00", sApdu);
        dev.Apdu(sApdu, rApdu);
        dev.PowerOff();
        return false;
    }
    /// 断开连接
    virtual bool UnLink(CCID_Device& dev, TextPrinter& printer)
    {
        return _ccidLinker.UnLink(dev, printer);
    }
};
//--------------------------------------------------------- 
/// CCID读卡器EscapeCommand测试器
class CCID_EscapeCommandTestCase : public ITestCase<CCID_Device>
{
public:
    /**
     * @brief EscapeCommand测试
     * 
     * @param [in] testObj 需要操作的设备
     * @param [in] testArg 参数 "[Name:<SAM>][VID:<1DFC>][PID:<8903>]"
     * @param [in] printer 文本输出器
     */
    virtual bool Test(Ref<CCID_Device>& testObj, const ByteArray& testArg, TextPrinter& printer)
    {
        string vid;
        string pid;
        string devName = testArg.GetString();

        ArgParser parser;
        StringArguments cfg;
        if(parser.Parse(testArg.GetString(), cfg))
        {
            cfg.Get("Name", devName);
            cfg.Get("VID", vid);
            cfg.Get("PID", pid);
        }

        printer.TextPrint(TextPrinter::TextLogger, "CCID_Device::EscapeCommand");
        testObj->SetMode(CCID_Device::EscapeCommand);
        // 当前已经支持
        if(CCID_DeviceHelper::PowerOn(testObj, devName.c_str(), NULL, SIZE_EOF) != DevHelper::EnumSUCCESS)
        {
            printer.TextPrint(TextPrinter::TextLogger, "EscapeCommand已支持");
            return true;
        }

        // 修改注册表并重新尝试
        bool isChanged = false;
        printer.TextPrint(TextPrinter::TextLogger, "SetEscapeCommandEnable");
        bool isEnable = WinCCID_EscapeCommandHelper::SetEscapeCommandEnable(vid.c_str(), pid.c_str(), true, &isChanged);
        if(isChanged)
        {
            printer.TextPrint(TextPrinter::TextError, "修改注册表成功,请拔插设备或重启电脑后启动程序进行升级");
            return false;
        }
        if(!isEnable)
        {
            printer.TextPrint(TextPrinter::TextError, "修改注册表失败,请以管理员权限重新运行升级程序");
            return false;
        }

        return true;
    }
};
//--------------------------------------------------------- 
/// CCID读卡器文件行升级器 
class CCID_UpdaterTestCase : public ITestCase<CCID_Device>
{
protected:
    /// 发送的APDU 
    ByteBuilder _sApdu;
public:
    CCID_UpdaterTestCase()
    {
        DevCommand::FromAscii("FF 00 83 00", _sApdu);
    }
    /// 升级文件行
    virtual bool Test(Ref<CCID_Device>& testObj, const ByteArray& testArg, TextPrinter&)
    {
        ByteBuilder rApdu(4);
        bool bApdu = false;
        switch(testObj->GetMode())
        {
        case CCID_Device::EscapeCommand:
            bApdu = testObj->Apdu(testArg, rApdu);
            break;
        case CCID_Device::ApduCommand:
            // 需要封装到指令头中 
            _sApdu += _itobyte(testArg.GetLength());
            _sApdu += testArg;

            bApdu = testObj->Apdu(_sApdu, rApdu);

            _sApdu.RemoveTail(testArg.GetLength() + 1);
            break;
        default:
            bApdu = true;
            break;
        }

        // 如果不是最后一行hex数据则判断状态码(是最后一行数据时,设备升级切换,会导致设备连接失败)
        if(DevUpdaterConvert::IsEOF(testArg))
        {
            bApdu = true;
        }
        else
        {
            ushort sw = ICCardLibrary::GetSW(rApdu);
            return bApdu && ICCardLibrary::IsSuccessSW(sw);
        }
        return bApdu;
    }
};
//--------------------------------------------------------- 
} // namespace updater
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_CCID_DEVUPDATER_H_
//========================================================= 